package com.css.fxfzysx.modules.vabStructure.utils;

import com.css.fxfzysx.modules.vaolEngineering.utils.LeastSquareMethod;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class LeastSquareMethod1 {
    private BigDecimal[] xData;
    private BigDecimal[] yData;

    public static Map<String, BigDecimal> leastSquareMethod1(BigDecimal[] xData, BigDecimal[] yData) {
        return new LeastSquareMethod1(xData, yData).predict();
    }


    public Map<String, BigDecimal> predict() {
        // 计算n
        BigDecimal n = BigDecimal.valueOf(xData.length);
        // 计算x，y，xy，x²的总和
        BigDecimal totalX = BigDecimal.ZERO;
        BigDecimal totalY = BigDecimal.ZERO;
        BigDecimal totalXY = BigDecimal.ZERO;
        BigDecimal totalX2 = BigDecimal.ZERO;
        for (int i = 0; i < xData.length; i++) {
            totalX = xData[i].add(totalX);
            totalY = yData[i].add(totalY);
            totalXY = totalXY.add(xData[i].multiply(yData[i]));
            totalX2 = totalX2.add(xData[i].multiply(xData[i]));
        }
        // 计算x和y的均值
        BigDecimal meanX = totalX.divide(n,4,BigDecimal.ROUND_HALF_UP);
        BigDecimal meanY = totalY.divide(n,4,BigDecimal.ROUND_HALF_UP);
        // 计算斜率b
        BigDecimal b = (totalXY.subtract(n.multiply(meanX).multiply(meanY))).divide
                (totalX2.subtract(n.multiply(meanX).multiply(meanX)),4,BigDecimal.ROUND_HALF_UP);
        // 计算截距a
        BigDecimal a = meanY.subtract(b.multiply(meanX));

        // 计算R Square和标准误差
        BigDecimal ssr = BigDecimal.ZERO;
        BigDecimal sst = BigDecimal.ZERO;

        for (int i = 0; i < xData.length; i++) {
            BigDecimal yHat = a.add(b.multiply(xData[i]));
            ssr = ssr.add(yHat.subtract(yData[i]).pow(2));
            sst = sst.add(yData[i].subtract(meanY).pow(2));
        }
        BigDecimal rSquare = BigDecimal.ONE.subtract(ssr.divide(sst, 4, BigDecimal.ROUND_HALF_UP));
        BigDecimal standardError = n.subtract(BigDecimal.valueOf(2)).equals(BigDecimal.ZERO) ?BigDecimal.ZERO:BigDecimal.valueOf(Math.sqrt(ssr.divide(n.subtract(BigDecimal.valueOf(2)), 4, BigDecimal.ROUND_HALF_UP).doubleValue()));

        // 返回预测结果
        Map<String, BigDecimal> map = new HashMap<>();
        map.put("a", a);
        map.put("b", b);
        map.put("rs", standardError);
        map.put("r2", rSquare);
        return map;
    }

    public LeastSquareMethod1(BigDecimal[] xData, BigDecimal[] yData) {
        this.xData = xData;
        this.yData = yData;
    }
}
